﻿#region

using System;
using System.Collections.Generic;
using System.Data.SqlServerCe;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using MediaSage.Lib.Database;
using MediaSage.Lib.Plugin;
using MediaSage.Lib.Utilities;
using NHibernate;

#endregion

namespace MediaSage.Lib.Configuration
{
    #region Enumerations

    public enum MetadataSources
    {
        TVDB,
        IMDB,
        TMDB
    }

    #endregion Enumerations

    /// <summary>
    ///     Struct used by plugins to return infomation about versioning and name
    ///     name - Simply that, the name of the plugin
    ///     Version # is majorVersion.minorVersion.buildNumber
    ///     Ex: 1.1.100
    /// </summary>
    public struct VersionInfo
    {
        #region Fields

        public int BuildNumber;
        public int MajorVersion;
        public int MinorVersion;
        public string Name;

        #endregion Fields
    }

    public class Config
    {
        #region Fields

        private readonly ConfigEntity _configEntity;
        public string BaseDirectory;
        public string DBLocation;
        public string DatabaseLocation;
        public bool DefaultConfig;
        public Logger Logger;
        public PluginManager PluginManager;
        public ThreadManager.ThreadManager ThreadManager;

        #endregion Fields

        #region Constructors

        public Config()
        {
            DefaultConfig = false;
            StartBugTrap();
#if DEBUG
            RegistryHelper.DeleteKey(@"SOFTWARE\MediaSage\DatabaseLocation");
#endif
            if (RegistryHelper.KeyExists(@"SOFTWARE\MediaSage\InstallRoot"))
            {
                BaseDirectory = (string)RegistryHelper.GetKeyValue(@"SOFTWARE\MediaSage", "InstallRoot");
            }
            else
            {
                BaseDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            }
            if (RegistryHelper.KeyExists(@"SOFTWARE\MediaSage\DatabaseLocation"))
            {
                DBLocation = (string)RegistryHelper.GetKeyValue(@"SOFTWARE\MediaSage", "DatabaseLocation");
            }
            else
            {
                DBLocation =
                    Path.Combine(
                        path1:
                            RegistryHelper.KeyExists(@"SOFTWARE\MediaSage\InstallRoot")
                                ? BaseDirectory
                                : Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
                        path2: "MediaSage.sdf");
            }
            bool dbInit = false;
            if (!File.Exists(DBLocation))
            {
                DBLocation = Path.Combine(path1: Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
                                          path2: "MediaSage.sdf");
                if (!File.Exists(DBLocation))
                {
                    var sqlCeEngine = new SqlCeEngine("Data Source=" + DBLocation);
                    sqlCeEngine.CreateDatabase();

                    DBUtil.CreateTables(DBLocation);
                    RegistryHelper.SetKeyValue(@"SOFTWARE\MediaSage", "DatabaseLocation", DBLocation);
                    dbInit = true;
                }
            }

            if (!dbInit)
            {
                DBUtil.Init(DatabaseLocation);
            }
            _configEntity = (ConfigEntity)DBUtil.GetSession().CreateCriteria(typeof(ConfigEntity)).UniqueResult();
            if (_configEntity == null)
            {
                _configEntity = new ConfigEntity();
                CreateDefaultConfig(DBUtil.GetSession());
                DefaultConfig = true;
                _configEntity = (ConfigEntity)DBUtil.GetSession().CreateCriteria(typeof(ConfigEntity)).UniqueResult();
            }
            Logger = new Logger(this);
            PluginManager = new PluginManager(this);

            // Now output the configuration we have
            Logger.Log(Logger.Levels.INFO, strings.DATABASE_LOCATION + DatabaseLocation);
            Logger.Log(Logger.Levels.INFO, strings.FORCE_RESCAN + ForceRescan.ToString());
            Logger.Log(Logger.Levels.INFO, strings.IMAGE_STORAGE + ImageDir);
            Logger.Log(Logger.Levels.INFO, strings.GET_ALL_IMAGES + GetAllImages.ToString());
            Logger.Log(Logger.Levels.INFO, strings.GUESS_THRESHOLD + GuessScoreThreshold);
            Logger.Log(Logger.Levels.INFO, strings.NUMBER_RETURNED_FROM_GUESS + NumberOfReturnedMovies);
            Logger.Log(Logger.Levels.INFO, strings.SCAN_FREQUENCY + ScanFrequency + " seconds");
            Logger.Log(Logger.Levels.INFO, strings.MAX_IMAGES + MaxImageCount);
            Logger.Log(Logger.Levels.INFO, strings.LOGFILE + LogFile);
            Logger.Log(strings.RESCAN_FREQUENCY + RescanFrequency + " days");
            Logger.Log("Maximum number of worker threads: " + MaxWorkerThreads);
            Logger.Log("Thread Timeout (seconds): " + ThreadTimeout);

            if (FileSystems != null)
            {
                foreach (FileSystemEntity st in FileSystems)
                {
                    Logger.Log(Logger.Levels.INFO, strings.SCAN_FILESYSTEM + st.directory);
                }
            }
            else
            {
                FileSystems = new List<FileSystemEntity>();
            }
            if (MediaTypes != null)
            {
                foreach (MediaFileTypesEntity st in MediaTypes)
                {
                    Logger.Log(Logger.Levels.INFO, strings.MEDIA_FILE_TO_SCAN + st.Description);
                    Logger.Log(Logger.Levels.INFO, strings.EXTENSION + st.Extension);
                }
            }
            else
            {
                MediaTypes = new List<MediaFileTypesEntity>();
            }
            if (Plugins != null)
            {
                foreach (PluginEntity st in Plugins)
                {
                    Logger.Log(Logger.Levels.INFO,
                               strings.PROVIDER + " " + st.Name + " " + st.Location + " " + st.MajorVersion + "." +
                               st.MinorVersion + "." + st.BuildNumber);
                }
            }
            else
            {
                Plugins = new List<PluginEntity>();
            }
            ThreadManager = new ThreadManager.ThreadManager(this);
        }

        #endregion Constructors

        #region Properties

        public MediaMergeType MergeType
        {
            set { _configEntity.MergeType = value; }
            get { return _configEntity.MergeType; }
        }

        public bool MergeOnPersonName
        {
            set { _configEntity.MergeOnPersonName = value; }
            get { return _configEntity.MergeOnPersonName; }
        }

        public bool ConvertImages
        {
            set { _configEntity.ConvertImages = value; }
            get { return _configEntity.ConvertImages; }
        }

        public EImageFormat ConvertImageToType
        {
            set { _configEntity.ConvertImageToType = value; }
            get { return _configEntity.ConvertImageToType; }
        }

        public bool CreateImageThumbnails
        {
            set { _configEntity.CreateImageThumbnails = value; }
            get { return _configEntity.CreateImageThumbnails; }
        }

        public int DBLogLevel
        {
            set { _configEntity.DBLogLevel = value; }
            get { return _configEntity.DBLogLevel; }
        }

        public IList<FileSystemEntity> FileSystems
        {
            set { _configEntity.FileSystems = value; }
            get { return _configEntity.FileSystems; }
        }

        public bool ForceRescan
        {
            set { _configEntity.ForceRescan = value; }
            get { return _configEntity.ForceRescan; }
        }

        public bool GetAllImages
        {
            set { _configEntity.GetAllImages = value; }
            get { return _configEntity.GetAllImages; }
        }

        public int GuessScoreThreshold
        {
            set { _configEntity.GuessScoreThreshold = value; }
            get { return _configEntity.GuessScoreThreshold; }
        }

        public string ImageDir
        {
            set { _configEntity.ImageDir = value; }
            get { return _configEntity.ImageDir; }
        }

        public string LogFile
        {
            set { _configEntity.LogFile = value; }
            get { return _configEntity.LogFile; }
        }

        public int LogLevel
        {
            set { _configEntity.LogLevel = value; }
            get { return _configEntity.LogLevel; }
        }

        public int MaxImageCount
        {
            set { _configEntity.MaxImageCount = value; }
            get { return _configEntity.MaxImageCount; }
        }

        public int MaxWorkerThreads
        {
            set { _configEntity.MaxWorkerThreads = value; }
            get { return _configEntity.MaxWorkerThreads; }
        }

        public IList<MediaFileTypesEntity> MediaTypes
        {
            set { _configEntity.MediaTypes = value; }
            get { return _configEntity.MediaTypes; }
        }

        public int NumberOfReturnedMovies
        {
            set { _configEntity.NumberOfReturnedMoviesFromGuess = value; }
            get { return _configEntity.NumberOfReturnedMoviesFromGuess; }
        }

        public string PluginDirectory
        {
            set { _configEntity.PluginDirectory = value; }
            get { return _configEntity.PluginDirectory; }
        }

        public IList<PluginEntity> Plugins
        {
            set { _configEntity.Plugins = value; }
            get { return _configEntity.Plugins; }
        }

        /// <summary>
        /// Frequency (In seconds) we scan file systems for changes
        /// </summary>
        public int ScanFrequency
        {
            set { _configEntity.ScanFrequency = value; }
            get { return _configEntity.ScanFrequency; }
        }

        /// <summary>
        /// Frequency (in days) we rescan titles for updates
        /// </summary>
        public int RescanFrequency
        {
            set { _configEntity.RescanFrequency = value; }
            get { return _configEntity.RescanFrequency; }
        }

        public int ThreadTimeout
        {
            set { _configEntity.ThreadTimeout = value; }
            get { return _configEntity.ThreadTimeout; }
        }

        public bool UpdateAutomatically
        {
            set { _configEntity.UpdateAutomatically = value; }
            get { return _configEntity.UpdateAutomatically; }
        }

        public string UpdateURL
        {
            set { _configEntity.UpdateURL = value; }
            get { return _configEntity.UpdateURL; }
        }

        #endregion Properties

        #region Methods

        public void WriteConfig()
        {
            Logger.Log("Entering Config.WriteConfig()");
            ITransaction transaction = DBUtil.GetSession().BeginTransaction();

            DBUtil.GetSession().SaveOrUpdate(_configEntity);
            transaction.Commit();
            transaction.Dispose();
            DBUtil.GetSession().Refresh(_configEntity);
            Logger.Log("Exiting Config.WriteConfig()");
        }

        private void CreateDefaultConfig(ISession session)
        {
            // TODO: Make these paths more inline with the installation
            if (RegistryHelper.KeyExists(@"SOFTWARE\MediaSage\InstallRoot"))
            {
                BaseDirectory = (string)RegistryHelper.GetKeyValue(@"SOFTWARE\MediaSage", "InstallRoot");
            }
            else
            {
                BaseDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                RegistryHelper.SetKeyValue(@"SOFTWARE\MediaSage", "InstallRoot", BaseDirectory);
            }
            ITransaction transaction = session.BeginTransaction();
            _configEntity.MaxWorkerThreads = Environment.ProcessorCount;
            _configEntity.ThreadTimeout = 180;
            _configEntity.ForceRescan = false;
#if DEBUG
            _configEntity.GetAllImages = false;
            _configEntity.MaxImageCount = 3;
#else
            _configEntity.GetAllImages = true;
#endif
            _configEntity.CreateImageThumbnails = true;
            _configEntity.GuessScoreThreshold = 95;
            if (BaseDirectory != null)
            {
                _configEntity.ImageDir = Path.Combine(BaseDirectory, "Images");
                _configEntity.PluginDirectory = Path.Combine(BaseDirectory, "Plugins");
            }
            _configEntity.MergeType = MediaMergeType.WRITE_IF_LARGER;

#if DEBUG
            _configEntity.DBLogLevel = 0;
#else
            _configEntity.DBLogLevel=2;
#endif

            _configEntity.ImageDir = Path.Combine(BaseDirectory, "Images");

            if (!Directory.Exists(_configEntity.ImageDir))
            {
                try
                {
                    Directory.CreateDirectory(_configEntity.ImageDir);
                }
                catch
                {
                }
            }
            if (!Directory.Exists(_configEntity.PluginDirectory))
            {
                try
                {
                    Directory.CreateDirectory(_configEntity.PluginDirectory);
                }
                catch (Exception)
                {
                }
            }
            _configEntity.LogFile = @"c:\MediaSage\logfile.log";
            _configEntity.LogLevel = 2;
            _configEntity.NumberOfReturnedMoviesFromGuess = 10;
            _configEntity.ScanFrequency = 300;
            _configEntity.RescanFrequency = 7;
            _configEntity.ConvertImageToType = EImageFormat.JPEG;

            var extensions = new string[17, 2]
                                 {
                                     {
                                         "AVI",
                                         "Common video container format.  AVI is the abbreviation for Audio Video Interleve format developed by Microsoft"
                                     },
                                     {"263", "H.263 encoded video file"},
                                     {"264", "H.264/MPEG-4 AVC video file"},
                                     {"bdmv", "Blu-ray information file"},
                                     {"divx", "DivX Media Format"},
                                     {"dvr-ms", "Microsoft Digital Video Recording"},
                                     {"m2t", "MPEG movie file"},
                                     {"m2ts", "MPEG-2 stream (Blu-Ray)"},
                                     {"m4v", "MPEG-4 video file format"},
                                     {"mkv", "Matroska video-audio multimedia file"},
                                     {"mov", "Apple QuickTime digital movie file"},
                                     {"mp4", "MPEG-4 video file format"},
                                     {"mpeg", "MPEG Movie"},
                                     {"mpg", "ProgDVB MPEG2 video file"},
                                     {"wmv", "Windows Media Video"},
                                     {"xvid", "XviD Codec"},
                                     {"wtv", "Windows Media Center recorded television file"}
                                 };
            for (int i = 0; i < extensions.Length / 2; i++)
            {
                var tmp = new MediaFileTypesEntity { Description = extensions[i, 1], Extension = extensions[i, 0] };
                _configEntity.AddMediaType(tmp);
                _configEntity.SaveOrUpdate();
            }
            _configEntity.SaveOrUpdate();
        }

        [Conditional("RELEASE")]
        private void StartBugTrap()
        {
            /*            ExceptionHandler.AppName = "MediaSageLib";
                        ExceptionHandler.Flags = FlagsType.DetailedMode | FlagsType.EditMail;
                        ExceptionHandler.DumpType = MinidumpType.WithProcessThreadData;
                        ExceptionHandler.SupportEMail = "mediasage@ymail.com";
                        ExceptionHandler.InstallHandler();
                        ExceptionHandler.InstallSehFilter();
             */
        }

        #endregion Methods
    }
}